package com.rookie.im.core.server;

import com.rookie.im.core.config.AppConfig;
import com.rookie.im.core.server.handler.ServerHandler;
import com.rookie.im.core.server.handler.WebSocketMessageDecoder;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

public class ImServer {
	private int port;
	private EventLoopGroup bossGroup;
	private EventLoopGroup workerGroup;
	private Channel channel;
	
	public ImServer(AppConfig.WebsocketConfig config) {
		port = config.getPort();
		bossGroup = new NioEventLoopGroup(config.getBoosThreadSize());
		workerGroup = new NioEventLoopGroup(config.getWorkerThreadSize());
	}
	
	public void run() {
		try {
			ServerBootstrap bootstrap = new ServerBootstrap();
			bootstrap.group(bossGroup, workerGroup)
				.channel(NioServerSocketChannel.class)
				.option(ChannelOption.SO_BACKLOG, 10240)
				.option(ChannelOption.SO_REUSEADDR, true)
				.childOption(ChannelOption.TCP_NODELAY, true)
				.childOption(ChannelOption.SO_KEEPALIVE, true)
				.childHandler(new ChannelInitializer<SocketChannel>() {

					@Override
					protected void initChannel(SocketChannel ch) throws Exception {
						ChannelPipeline pipeline = ch.pipeline();
						pipeline.addLast("http-code", new HttpServerCodec());
                        pipeline.addLast("http-chunk", new ChunkedWriteHandler());
						pipeline.addLast("aggregator", new HttpObjectAggregator(65535));
						pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
						pipeline.addLast(new WebSocketMessageDecoder());
						pipeline.addLast(new ServerHandler());
					}
				});
			channel = bootstrap.bind(port).sync().channel();
			System.out.println("启动成功");
			Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
			
			channel.closeFuture().sync();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Thread.currentThread().interrupt();
		} finally {
			shutdown();
		}
	}
	
	public void shutdown() {
		if (channel != null) {
			channel.close();
		}
		if (bossGroup != null) {
			bossGroup.shutdownGracefully();
		}
		if (workerGroup != null) {
			workerGroup.shutdownGracefully();
		}
	}

}
